<template>
  <div
    ref="sxUploadImage"
    class="sxUploadImage"
    tabindex="-1"
    @focus="handleDivFocus(true)"
    @blur="handleDivFocus(false)"
  >
    <div class="sxUploadImage__imageList">
      <div
        v-for="items in innerImgList"
        :key="items.id"
        class="sxUploadImage__imgItems"
        :style="imgItemsStyle"
      >
        <div v-if="items.status == 'ready'" class="sxUploadImage__progress">
          <el-progress type="circle" :width="100" :percentage="items.progress"></el-progress>
        </div>
        <div v-else class="sxUploadImage__img">
          <SxImage :src="items.filePath && ImgUrlFilter(items.filePath)" :alt="items.name" />
          <span class="sxUploadImage__img-actions">
            <span class="sxUploadImage__img-preview" @click="handlePictureCardPreview(items)">
              <i class="el-icon-zoom-in"></i>
            </span>
            <span
              v-if="!disabled"
              class="sxUploadImage__img-delete"
              @click="handlePictureDelete(items)"
            >
              <i class="el-icon-delete"></i>
            </span>
          </span>
        </div>
      </div>
      <div
        v-if="disabled ? false : !isLimit"
        class="sxUploadImage__imgItems sxUploadImage__imgItems-uploader"
        :style="imgItemsStyle"
      >
        <el-upload
          ref="upload"
          class="sxUploadImage__uploader"
          :class="{ 'sxUploadImage__uploader-disabled': isLimit }"
          :disabled="isLimit"
          action="#"
          :limit="limit"
          drag
          :multiple="multiple"
          :file-list="innerImgList"
          :show-file-list="false"
          :http-request="uploadFile"
        >
          <slot>
            <div class="sxUploadImage__uploadBtn">
              <i :style="{ fontSize: iconSize }" class="el-icon-plus"></i>
              <span>上传图片</span>
              <span class="sxUploadImage__tips">
                <span style="color:red">*</span>
                最多上传{{ limit }}张
              </span>
            </div>
          </slot>
        </el-upload>
      </div>
    </div>
    <div v-show="!disabled" class="sxUploadImage__bottomTips">
      <span v-if="uploadImageIsFocus" class="sxUploadImage__bottomTips-open">
        *
        已启用粘贴（ctrl+v）上传图片功能，仅支持QQ/微信等软件截图或者网页上复制的图片
      </span>
      <span v-else class="sxUploadImage__bottomTips-close">* 点击我开启粘贴上传，仅支持QQ/微信等软件截图或者网页上复制的图片</span>
    </div>
    <SxViewer ref="viewer" />
  </div>
</template>

<script>
import axios from "axios";
import { getToken } from "@/utils/auth";
import { ImgUrl } from "@Components/assets/js/config";
import SxImage from "@Components/Image";
import SxViewer from "@Components/Viewer";
import { ImgUrlFilter } from "@Components/assets/js/filter";
import { debounce } from "@/utils";

export default {
  desc: "上传图片",
  name: "SxUploadImage",
  components: {
    SxImage,
    SxViewer
  },
  props: {
    // 是否禁用上传
    disabled: {
      type: Boolean,
      default: false
    },
    showLimitMessage: {
      type: Boolean,
      default: true
    },
    limit: {
      type: Number,
      default: 5
    },
    fileUrl: {
      type: String
    },
    tips: {
      type: String
    },
    uploadParam: {
      type: Object,
      default() {
        return {};
      }
    },
    fileList: {
      type: Array,
      default() {
        return [];
      }
    }
  },
  data() {
    return {
      ImgUrlFilter,
      uploadImageIsFocus: false,
      dialogImageUrl: "",
      dialogVisible: false,
      actionUrl: ImgUrl,
      innerImgList: [],
      iconSize: "26px",
      imgItemsStyle: {
        width: "100px",
        height: "100px"
      },
      uploadFileSuccessDebounce: null
    };
  },
  computed: {
    isLimit() {
      let l = this.innerImgList.length;
      return l === this.limit || l > this.limit;
    },
    multiple() {
      return this.limit > 1;
    }
  },
  watch: {
    // TODO: 优化判断
    fileList: {
      handler(val, preVal) {
        if (!Array.isArray(preVal)) {
          return this.syncFileListData(val);
        }
        if (val.length !== preVal.length) {
          return this.syncFileListData(val);
        }
        const flag = val.some(i => {
          return preVal.findIndex(j => i.id === j.id) === -1;
        });
        if (flag) {
          return this.syncFileListData(val);
        }
      },
      immediate: true,
      deep: true
    }
  },
  mounted() {
    this.$refs.sxUploadImage.addEventListener("paste", this.handlePastUpload);
    this.uploadFileSuccessDebounce = debounce(this.uploadFileSuccess, 500);
  },
  created() {},
  methods: {
    // 处理粘贴上传
    handlePastUpload(e) {
      try {
        let file;
        let len = e.clipboardData.items.length;
        for (let index = 0; index < len; index++) {
          let item = e.clipboardData.items[index];
          if (item.type.indexOf("image") !== -1) {
            file = item.getAsFile();
          }
        }
        // 没有发现文件
        if (!file)
          return this.$showMessage({ message: "粘贴内容非支持的类型" });
        // 如果不在聚焦状态或者禁用状态，则不触发上传
        if (this.uploadImageIsFocus && !this.disabled) {
          this.uploadFile({ file });
        }
      } catch (error) {
        this.$showMessage({
          message: "当前浏览器不支持，可以换成谷歌、edge等浏览器"
        });
      }
    },
    // bool： true=聚焦，false=失焦
    handleDivFocus(bool) {
      this.uploadImageIsFocus = bool;
    },
    getImageList() {
      if (this.multiple) {
        return this.innerImgList.map(i => i);
      } else {
        return this.innerImgList.map(i => i);
      }
    },
    syncFileListData(val) {
      if (this.multiple) {
        this.innerImgList = val.map(i => i);
      } else {
        this.innerImgList = val.map(i => i);
      }
    },
    handleFileItemStruct(
      id,
      name,
      filePath = "#",
      status = "success",
      progress = 100
    ) {
      return {
        id,
        name,
        filePath,
        status,
        progress
      };
    },
    handleProgress(event) {
      return Math.round(100 * (event.loaded / event.total));
    },
    checkLimit() {
      if (!this.isLimit) return false;
      this.$sxMessage({
        type: "warning",
        message: `最多上传${this.limit}张图片`
      });
      return true;
    },
    uploadRequest(config) {
      const formData = new FormData();
      formData.append("file", config.formData);
      return new Promise(resolve => {
        axios({
          url: process.env.VUE_APP_BASE_API + "/common/upload",
          method: "POST",
          data: formData,
          headers: {
            // 表示上传的是文件,而不是普通的表单数据
            Authorization: "Bearer " + getToken(),
            "Content-Type": "multipart/form-data;"
          },
          onUploadProgress: config.onUploadProgress
        }).then(res => resolve(res));
      });
    },
    async uploadFile(files) {
      // 超出上传张数
      if (this.checkLimit()) return;

      const file = files.file;
      const fileItem = this.handleFileItemStruct(
        file.uid || new Date().getTime(),
        file.name,
        "#",
        "ready",
        0
      );
      let res = await this.uploadRequest({
        formData: file,
        onUploadProgress: e => {
          fileItem.progress = this.handleProgress(e);
        }
      });
      const { code, fileName, url, msg } = res.data;
      if (code == 200) {
        fileItem.id = fileName;
        fileItem.name = fileName;
        fileItem.filePath = url;
        fileItem.status = "success";
        this.fileList.push(fileItem);
        this.uploadFileSuccessDebounce();
      } else {
        this.$showMessage({
          type: "warning",
          message: msg
        });
      }
    },
    uploadFileSuccess() {
      this.$emit(
        "uploadFile",
        this.fileList.map(i => i.filePath)
      );
      this.$emit("upload-success", this.getImageList());
    },
    handlePictureCardPreview(file) {
      const index = this.innerImgList.findIndex(i => i.id === file.id);
      this.$refs.viewer.update(
        this.innerImgList.map(i => ImgUrlFilter(i.filePath)),
        index
      );
    },
    handlePictureDelete(file) {
      const idx = this.innerImgList.filter(i => i.id != file.id);
      this.$emit(
        "uploadFile",
        idx.map(i => i.filePath).filter(i => i.length != 0)
      );
      // this.innerImgList.splice(idx, 1)
    }
  }
};
</script>

<style scoped lang="scss">
.sxUploadImage {
  &:focus {
    outline: none;
  }

  /deep/ .el-upload-dragger {
    width: 100%;
    height: 100%;
    border: none;
    background-color: transparent;
    border-radius: unset;
    overflow: visible;
  }
  &__bottomTips {
    position: relative;
    height: 30px;
    font-size: 12px;
    span {
      top: 0;
      margin-top: 10px;
      position: absolute;
    }
    &-open {
      color: $Primary;
    }
    &-close {
      color: $Warning;
    }
  }
  /deep/ .el-upload {
    width: 100%;
    height: 100%;
    &:focus {
      color: #666;
      border-color: #666;
    }
  }
  /deep/ .el-upload--picture-card {
    width: 100%;
    height: 100%;
  }
  /deep/ .el-upload-list--picture-card {
    .el-upload-list__item {
      width: 100%;
      height: 100%;
    }
  }
  &__tips {
    transform: scale(0.9);
  }
  // 因为IE不支持display:grid; 此代码是为了兼容IE10以上的布局
  @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
    /* IE10+ CSS styles go here */
    &__imageList {
      display: flex;
      flex-wrap: wrap;
    }
    &__imgItems {
      margin: 10px;
      width: 100px;
    }
  }
  &__imageList {
    display: grid;
    grid-template-columns: repeat(auto-fill, 100px);
    grid-column-gap: 10px;
    grid-row-gap: 10px;
  }
  &__imgItems {
    border: solid 1px #999;
    cursor: pointer;
    border-radius: 4px;
    overflow: hidden;
    &:focus {
      outline: none;
    }
    &-uploader {
      border: dashed 1px #666;
    }
  }

  &__img {
    position: relative;
    width: 100%;
    height: 100%;
    img {
      width: 100%;
      height: 100%;
    }
    &-actions {
      position: absolute;
      top: 0;
      left: 0;
      display: flex;
      width: 100%;
      height: 100%;
      justify-content: center;
      align-items: center;
      background-color: rgba($color: #000000, $alpha: 0.6);
      opacity: 0;
      transition: opacity 0.3s;
      &:hover {
        opacity: 1;
      }
    }
    &-preview,
    &-delete {
      color: #fff;
      font-size: 16px;
      margin: 0 5px;
    }
  }
  &__uploader {
    width: 100%;
    height: 100%;
    &:focus {
      outline: none;
      color: none;
    }
    &:hover {
      div,
      i,
      span {
        border-color: $Primary;
        color: $Primary;
      }
    }
    &-disabled {
      &:focus {
        outline: none;
        color: #666;
      }
      &:hover {
        div,
        i,
        span {
          border-color: #666;
          color: #666;
          cursor: not-allowed;
        }
      }
    }
  }
  &__uploadBtn {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
    &:focus {
      outline: none;
      i {
        outline: none;
      }
    }
    i {
      &:focus {
        outline: none;
      }
    }
    span {
      line-height: 1.2;
      margin-top: 5px;
      font-size: 14px;
      user-select: none;
    }
  }
}
</style>
